package imp

import (
	sqlc "bgs/db/sqlc"
	brandAdminGrpc "bgs/grpc/gen/service/brand_admin"
	"bgs/grpc/gen/shared/message"
	"bgs/util"
	"context"
	"fmt"
)

/****************************************************************************************/
/*                               brand_admin entity of helper                           */
/****************************************************************************************/

func transformBrandAdminEntityToPb(brandAdmin sqlc.BrandAdmin) *brandAdminGrpc.BrandAdminEntity {
	return &brandAdminGrpc.BrandAdminEntity{
		Id:        brandAdmin.ID,
		UserId:    brandAdmin.UserID,
		BrandId:   brandAdmin.BrandID,
		AliasName: brandAdmin.AliasName,
		Became:    sqlc.GoTimeToPBTimestamp(brandAdmin.Became),
		Remark:    brandAdmin.Remark.String,
	}
}

func mapBrandAdminEntityToPb(list []sqlc.BrandAdmin, f func(sqlc.BrandAdmin) *brandAdminGrpc.BrandAdminEntity) []*brandAdminGrpc.BrandAdminEntity {
	r := make([]*brandAdminGrpc.BrandAdminEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

/****************************************************************************************/
/*                               brand_admin entity of cmd                              */
/****************************************************************************************/

// BecomeBrandAdmin 成为品牌管理员
func (s *BrandAPIService) BecomeBrandAdmin(ctx context.Context, req *brandAdminGrpc.BecomeBrandAdminRequest) (res *brandAdminGrpc.BecomeBrandAdminResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_adminImp->BecomeBrandAdmin:%v", req)
	res = &brandAdminGrpc.BecomeBrandAdminResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	var brandAdmin sqlc.BrandAdmin
	userID := req.UserId
	brandID := req.BrandId
	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {
		empID, err := s.userService.EnsureUserAsBrandEmployee(ctx, q, userID, brandID)
		if err != nil {
			return
		}

		brandAdmin, err = q.UpsertBrandAdmin(ctx, sqlc.UpsertBrandAdminParams{
			UserID:    req.UserId,
			BrandID:   req.BrandId,
			AliasName: req.AliasName,
			Became:    sqlc.PBTimestampToGoTime(req.Became),
			RemotePk:  empID,
		})
		if err != nil {
			return err
		}
		slog.Info("2 insert brand_admin ok")

		user, err := q.GetUser(ctx, brandAdmin.UserID)
		if err != nil {
			return err
		}
		slog.Info("2 获取user ok")
		userRoles := user.Roles
		if !util.StringContains(userRoles, string(sqlc.EmUserRoleBrandAdmin)) {
			newUserRoles := append(userRoles, string(sqlc.EmUserRoleBrandAdmin))
			user, err = q.UpdateUserRoles(ctx, sqlc.UpdateUserRolesParams{
				ID:    brandAdmin.UserID,
				Roles: newUserRoles,
			})
			if err != nil {
				return
			}
			slog.Info("3 更新用户roles ok")
		}

		err = s.brandService.UpdateBrandStatFansCountSinceUpsertBrandFan(ctx, q, brandID)
		if err != nil {
			return
		}
		slog.Infof("4 更新品牌统计的admin_count ok")

		return
	})

	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	s.brandService.ClearCache(brandAdmin.BrandID)
	res.BrandAdmin = transformBrandAdminEntityToPb(brandAdmin)
	return
}

// UpdateBrandAdmin 更新品牌管理员
func (s *BrandAPIService) UpdateBrandAdmin(ctx context.Context, req *brandAdminGrpc.UpdateBrandAdminRequest) (res *brandAdminGrpc.UpdateBrandAdminResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_adminImp->UpdateBrandAdmin:%v", req)
	res = &brandAdminGrpc.UpdateBrandAdminResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	arg := sqlc.UpdateBrandAdminParams{
		ID:        req.Id,
		AliasName: req.AliasName,
		Remark:    sqlc.NSFromString(req.Remark),
	}
	brandAdmin, err := s.dao.Q.UpdateBrandAdmin(ctx, arg)

	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.BrandAdmin = transformBrandAdminEntityToPb(brandAdmin)
	return
}

// CancelBrandAdmin 取消品牌管理员
func (s *BrandAPIService) CancelBrandAdmin(ctx context.Context, req *brandAdminGrpc.CancelBrandAdminRequest) (res *brandAdminGrpc.CancelBrandAdminResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_adminImp->BecomeBrandAdmin:%v", req)
	res = &brandAdminGrpc.CancelBrandAdminResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	var brandAdmin sqlc.BrandAdmin

	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		brandAdmin, err = q.DeleteBrandAdmin(ctx, req.Id)
		if err != nil {
			return err
		}
		slog.Info("1 delete brand_admin ok")

		total, err := q.CountBrandAdminsByUserID(ctx, brandAdmin.UserID)
		if err != nil {
			return err
		}
		slog.Infof("2 CountBrandAdminsByUserID=>%d", total)

		if total == 0 {
			user, err := q.GetUser(ctx, brandAdmin.UserID)
			if err != nil {
				return err
			}
			slog.Info("3 获取user ok")
			userRoles := user.Roles

			newUserRoles := util.StringFilter(userRoles, func(s string) bool {
				return s != string(sqlc.EmUserRoleBrandAdmin)
			})
			user, err = q.UpdateUserRoles(ctx, sqlc.UpdateUserRolesParams{
				ID:    brandAdmin.UserID,
				Roles: newUserRoles,
			})
			if err != nil {
				return err
			}
			slog.Info("4 更新用户roles ok")
		}

		return
	})

	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.BrandAdmin = transformBrandAdminEntityToPb(brandAdmin)
	return
}

// CancelBrandAdmin 取消品牌管理员
func (s *BrandAPIService) IdentifiyBrandAdminEmployee(ctx context.Context, req *brandAdminGrpc.IdentifiyBrandAdminEmployeeRequest) (res *brandAdminGrpc.IdentifiyBrandAdminEmployeeResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_adminImp->IdentifiyBrandAdminEmployee:%v", req)
	res = &brandAdminGrpc.IdentifiyBrandAdminEmployeeResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	var brandAdmin sqlc.BrandAdmin

	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		brandAdmin, err = q.GetBrandAdmin(ctx, req.Id)
		if err != nil {
			return err
		}
		slog.Info("1 get brand_admin ok")

		if brandAdmin.RemotePk > 0 {
			err = fmt.Errorf("brandadmin already map a employee")
			return
		}

		err = s.brandService.IdentifiyBrandAdminEmployee(ctx, q, &brandAdmin)
		if err != nil {
			return err
		}
		slog.Info("2 IdentifiyBrandAdminEmployee ok")

		q.UpdateBrandAdminRemotePk(ctx, sqlc.UpdateBrandAdminRemotePkParams{
			ID:       brandAdmin.ID,
			RemotePk: brandAdmin.RemotePk,
		})
		slog.Info("3 更新用户roles ok")
		return
	})

	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.BrandAdmin = transformBrandAdminEntityToPb(brandAdmin)
	return
}

/****************************************************************************************/
/*                               brand_admin entity of query                            */
/****************************************************************************************/

// ListBrandAdminsByBrandID  获取品牌管理员
func (s *BrandAPIService) ListBrandAdminsByBrandID(ctx context.Context, req *brandAdminGrpc.ListBrandAdminsByBrandIDRequest) (res *brandAdminGrpc.ListBrandAdminsByBrandIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_adminImp->ListBrandAdminsByBrandID:%v", req)

	res = &brandAdminGrpc.ListBrandAdminsByBrandIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	total, err := s.dao.Q.CountBrandAdminsByBrandID(ctx, req.BrandId)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if total == 0 {
		// 不用继续调用listfunc
		return
	}
	arg := sqlc.ListBrandAdminsByBrandIDParams{
		Limit:   req.Limit,
		Offset:  req.Offset,
		BrandID: req.BrandId,
	}
	brandAdmins, err := s.dao.Q.ListBrandAdminsByBrandID(ctx, arg)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.BrandAdmins = mapBrandAdminEntityToPb(brandAdmins, transformBrandAdminEntityToPb)
	return
}

/****************************************************************************************/
/*                            brand_adminJoins entity of helper                         */
/****************************************************************************************/

func transformBrandAdminWithBrandOwnFlagByBrandIDAndUserIDEntityToPb(row sqlc.ListBrandAdminWithBrandOwnFlagsByBrandIDAndUserIDRow) *brandAdminGrpc.BrandAdminWithBrandOwnFlagByBrandIDAndUserIDEntity {
	return &brandAdminGrpc.BrandAdminWithBrandOwnFlagByBrandIDAndUserIDEntity{
		// brand_admin
		Id:        row.ID,
		UserId:    row.UserID,
		BrandId:   row.BrandID,
		AliasName: row.AliasName,
		Became:    sqlc.GoTimeToPBTimestamp(row.Became),
		Remark:    row.Remark.String,
		// additional
		IsBrandOwner: row.IsBrandOwner,
	}
}

func mapBrandAdminWithBrandOwnFlagByBrandIDAndUserIDEntityToPb(list []sqlc.ListBrandAdminWithBrandOwnFlagsByBrandIDAndUserIDRow, f func(sqlc.ListBrandAdminWithBrandOwnFlagsByBrandIDAndUserIDRow) *brandAdminGrpc.BrandAdminWithBrandOwnFlagByBrandIDAndUserIDEntity) []*brandAdminGrpc.BrandAdminWithBrandOwnFlagByBrandIDAndUserIDEntity {
	r := make([]*brandAdminGrpc.BrandAdminWithBrandOwnFlagByBrandIDAndUserIDEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transformBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserIDEntityToPb(row sqlc.ListBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserIDRow) *brandAdminGrpc.BrandAdminWithUserEntity {
	return &brandAdminGrpc.BrandAdminWithUserEntity{
		// brand_admin
		Id:        row.ID,
		UserId:    row.UserID,
		BrandId:   row.BrandID,
		AliasName: row.AliasName,
		Became:    sqlc.GoTimeToPBTimestamp(row.Became),
		Remark:    row.Remark.String,

		// user
		UserNickName: row.UserNickName,
		UserPic:      row.UserPic,
	}
}

func mapBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserIDEntityToPb(list []sqlc.ListBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserIDRow, f func(sqlc.ListBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserIDRow) *brandAdminGrpc.BrandAdminWithUserEntity) []*brandAdminGrpc.BrandAdminWithUserEntity {
	r := make([]*brandAdminGrpc.BrandAdminWithUserEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

/****************************************************************************************/
/*                            brand_adminJoins entity of query                          */
/****************************************************************************************/

// ListBrandAdminWithBrandOwnFlagsByBrandIDAndUserID  获取品牌管理员及品牌的拥有者标识
func (s *BrandAPIService) ListBrandAdminWithBrandOwnFlagsByBrandIDAndUserID(ctx context.Context, req *brandAdminGrpc.ListBrandAdminWithBrandOwnFlagsByBrandIDAndUserIDRequest) (res *brandAdminGrpc.ListBrandAdminWithBrandOwnFlagsByBrandIDAndUserIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_adminImp->ListBrandAdminWithBrandOwnFlagsByBrandIDAndUserID:%v", req)

	res = &brandAdminGrpc.ListBrandAdminWithBrandOwnFlagsByBrandIDAndUserIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	total, err := s.dao.Q.CountBrandAdminsByBrandID(ctx, req.BrandId)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if total == 0 {
		// 不用继续调用listfunc
		return
	}
	arg := sqlc.ListBrandAdminWithBrandOwnFlagsByBrandIDAndUserIDParams{
		Limit:   req.Limit,
		Offset:  req.Offset,
		BrandID: req.BrandId,
		UserID:  req.UserId,
	}
	brandAdminWithBrandOwnFlagsByBrandIDAndUserID, err := s.dao.Q.ListBrandAdminWithBrandOwnFlagsByBrandIDAndUserID(ctx, arg)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.BrandAdminWithBrandOwnFlags = mapBrandAdminWithBrandOwnFlagByBrandIDAndUserIDEntityToPb(brandAdminWithBrandOwnFlagsByBrandIDAndUserID, transformBrandAdminWithBrandOwnFlagByBrandIDAndUserIDEntityToPb)
	return
}

// ListBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserID  获取品牌管理员及用户信息并排除品牌拥有者
func (s *BrandAPIService) ListBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserID(ctx context.Context, req *brandAdminGrpc.ListBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserIDRequest) (res *brandAdminGrpc.ListBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_adminImp->ListBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserID:%v", req)

	res = &brandAdminGrpc.ListBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	q := s.dao.Q
	total, err := q.CountBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserID(ctx, sqlc.CountBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserIDParams{
		BrandID: req.BrandId,
		UserID:  req.UserId,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	brandAdminsWithoutBrandOwnerByBrandIDAndUserID, err := q.ListBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserID(ctx, sqlc.ListBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserIDParams{
		Limit:   req.Limit,
		Offset:  req.Offset,
		BrandID: req.BrandId,
		UserID:  req.UserId,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.BrandAdminWithUsers = mapBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserIDEntityToPb(brandAdminsWithoutBrandOwnerByBrandIDAndUserID, transformBrandAdminWithUsersWithoutBrandOwnerByBrandIDAndUserIDEntityToPb)
	return
}
